package com.loyal.dialog;

import android.content.Context;
import android.content.DialogInterface;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
import android.widget.LinearLayout;

import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.appcompat.widget.AppCompatTextView;

import com.loyal.R;

import java.lang.ref.WeakReference;

class MessageController {
    private final Context mContext;
    final MessageDialog mDialog;
    private final Window mWindow;

    private CharSequence mTitle;
    private CharSequence mMessage;

    Button mCancelButton;
    private CharSequence mCancelButtonText;
    Message mCancelButtonMessage;
    private Drawable mCancelButtonIcon;

    Button mOKButton;
    private CharSequence mOKButtonText;
    Message mOKButtonMessage;
    private Drawable mOKButtonIcon;

    private int mIconId = 0;
    private Drawable mIcon;
    private boolean fullScreen;

    private AppCompatImageView mIconView;
    private AppCompatTextView mTitleView;
    private AppCompatTextView mMessageView;

    Handler mHandler;

    private final View.OnClickListener mButtonHandler = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            final Message m;
            if (v == mCancelButton && mCancelButtonMessage != null) {
                m = Message.obtain(mCancelButtonMessage);
            } else if (v == mOKButton && mOKButtonMessage != null) {
                m = Message.obtain(mOKButtonMessage);
            } else {
                m = null;
            }

            if (m != null) {
                m.sendToTarget();
            }

            // Post a message so we dismiss after the above handlers are executed
            mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialog).sendToTarget();
        }
    };

    private static final class ButtonHandler extends Handler {
        // Button clicks have Message.what as the BUTTON{1,2,3} constant
        private static final int MSG_DISMISS_DIALOG = 1;

        private final WeakReference<DialogInterface> mDialog;

        public ButtonHandler(Looper looper, DialogInterface dialog) {
            super(looper);
            mDialog = new WeakReference<>(dialog);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            DialogInterface dialogInterface = mDialog.get();
            if (null == dialogInterface) return;
            switch (msg.what) {
                case DialogInterface.BUTTON_POSITIVE:
                case DialogInterface.BUTTON_NEGATIVE:
                case DialogInterface.BUTTON_NEUTRAL:
                    ((DialogInterface.OnClickListener) msg.obj).onClick(dialogInterface, msg.what);
                    break;

                case MSG_DISMISS_DIALOG:
                    ((DialogInterface) msg.obj).dismiss();
            }
        }
    }

    private static boolean shouldCenterSingleButton(Context context) {
        final TypedValue outValue = new TypedValue();
        context.getTheme().resolveAttribute(R.attr.alertDialogCenterButtons, outValue, true);
        return outValue.data != 0;
    }

    public MessageController(Context context, MessageDialog di, Window window) {
        mContext = context;
        mDialog = di;
        mWindow = window;
        mHandler = new ButtonHandler(Looper.myLooper(), di);
        /* We use a custom title so never request a window title */
        di.supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
    }

    public void installContent() {
        mDialog.setContentView(R.layout.dialog_message);
        setupView();
    }

    public void setTitle(CharSequence title) {
        mTitle = title;
        if (mTitleView != null) {
            mTitleView.setText(title);
        }
    }

    public void setMessage(CharSequence message) {
        mMessage = message;
        if (mMessageView != null) {
            mMessageView.setText(message);
        }
    }

    public void setFullScreen(boolean fullScreen) {
        this.fullScreen = fullScreen;
    }

    public boolean isFullScreen() {
        return fullScreen;
    }

    /**
     * Sets an icon, a click listener or a message to be sent when the button is clicked.
     * You only need to pass one of {@code icon}, {@code listener} or {@code msg}.
     *
     * @param whichButton Which button, can be one of
     *                    {@link DialogInterface#BUTTON_POSITIVE},
     *                    {@link DialogInterface#BUTTON_NEGATIVE}, or
     *                    {@link DialogInterface#BUTTON_NEUTRAL}
     * @param text        The text to display in positive button.
     * @param listener    The {@link DialogInterface.OnClickListener} to use.
     * @param msg         The {@link Message} to be sent when clicked.
     * @param icon        The (@link Drawable) to be used as an icon for the button.
     */
    public void setButton(int whichButton, CharSequence text, DialogInterface.OnClickListener listener, Message msg, Drawable icon) {

        if (msg == null && listener != null) {
            msg = mHandler.obtainMessage(whichButton, listener);
        }

        switch (whichButton) {
            //Right side
            case DialogInterface.BUTTON_POSITIVE:
                mOKButtonText = text;
                mOKButtonMessage = msg;
                mOKButtonIcon = icon;
                break;
            //Left side
            case DialogInterface.BUTTON_NEGATIVE:
                mCancelButtonText = text;
                mCancelButtonMessage = msg;
                mCancelButtonIcon = icon;
                break;
            default:
                throw new IllegalArgumentException("Button does not exist");
        }
    }

    /**
     * Specifies the icon to display next to the alert title.
     *
     * @param resId the resource identifier of the drawable to use as the icon,
     *              or 0 for no icon
     */
    public void setIcon(int resId) {
        mIcon = null;
        mIconId = resId;

        if (mIconView != null) {
            if (resId != 0) {
                mIconView.setVisibility(View.VISIBLE);
                mIconView.setImageResource(mIconId);
            } else {
                mIconView.setVisibility(View.GONE);
            }
        }
    }

    /**
     * Specifies the icon to display next to the alert title.
     *
     * @param icon the drawable to use as the icon or null for no icon
     */
    public void setIcon(Drawable icon) {
        mIcon = icon;
        mIconId = 0;

        if (mIconView != null) {
            if (icon != null) {
                mIconView.setVisibility(View.VISIBLE);
                mIconView.setImageDrawable(icon);
            } else {
                mIconView.setVisibility(View.GONE);
            }
        }
    }

    /**
     * @param attrId the attributeId of the theme-specific drawable
     *               to resolve the resourceId for.
     * @return resId the resourceId of the theme-specific drawable
     */
    public int getIconAttributeResId(int attrId) {
        TypedValue out = new TypedValue();
        mContext.getTheme().resolveAttribute(attrId, out, true);
        return out.resourceId;
    }

    public Button getButton(int whichButton) {
        switch (whichButton) {
            case DialogInterface.BUTTON_POSITIVE:
                return mOKButton;
            case DialogInterface.BUTTON_NEGATIVE:
                return mCancelButton;
            default:
                return null;
        }
    }

    private void setupView() {
        final ViewGroup topPanel = mWindow.findViewById(R.id.titlePanel);
        final ViewGroup buttonPanel = mWindow.findViewById(R.id.buttonPanel);

        setupTitle(topPanel);
        setupContent();
        setupButtons(buttonPanel);
    }

    private void setupTitle(ViewGroup topPanel) {
        mIconView = mWindow.findViewById(android.R.id.icon);
        final boolean hasTextTitle = !TextUtils.isEmpty(mTitle);
        if (hasTextTitle) {
            // Display the title if a title is supplied, else hide it.
            mTitleView = mWindow.findViewById(R.id.alertTitle);
            mTitleView.setText(mTitle);

            // Do this last so that if the user has supplied any icons we
            // use them instead of the default ones. If the user has
            // specified 0 then make it disappear.
            if (mIconId != 0) {
                mIconView.setImageResource(mIconId);
            } else if (mIcon != null) {
                mIconView.setImageDrawable(mIcon);
            } else {
                // Apply the padding from the icon to ensure the title is
                // aligned correctly.
                mTitleView.setPadding(mIconView.getPaddingLeft(), mIconView.getPaddingTop(), mIconView.getPaddingRight(), mIconView.getPaddingBottom());
                mIconView.setVisibility(View.GONE);
            }
        } else {
            // Hide the title template
            mIconView.setVisibility(View.GONE);
            topPanel.setVisibility(View.GONE);
        }
    }

    private void setupContent() {
        // Special case for users that only want to display a String
        mMessageView = mWindow.findViewById(android.R.id.message);
        if (mMessageView == null) {
            return;
        }

        if (mMessage != null) {
            mMessageView.setText(mMessage);
        } else {
            mMessageView.setVisibility(View.GONE);
        }
    }

    private void setupButtons(ViewGroup buttonPanel) {
        int BIT_BUTTON_POSITIVE = 1;
        int BIT_BUTTON_NEGATIVE = 2;
        int whichButtons = 0;
        mCancelButton = mWindow.findViewById(R.id.cancel);
        mCancelButton.setOnClickListener(mButtonHandler);

        int mButtonIconDimen = 0;
        if (TextUtils.isEmpty(mCancelButtonText) && mCancelButtonIcon == null) {
            mCancelButton.setVisibility(View.GONE);
        } else {
            mCancelButton.setText(mCancelButtonText);
            if (mCancelButtonIcon != null) {
                mCancelButtonIcon.setBounds(0, 0, mButtonIconDimen, mButtonIconDimen);
                mCancelButton.setCompoundDrawables(mCancelButtonIcon, null, null, null);
            }
            mCancelButton.setVisibility(View.VISIBLE);
            whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
        }

        mOKButton = mWindow.findViewById(R.id.ok);
        mOKButton.setOnClickListener(mButtonHandler);

        if (TextUtils.isEmpty(mOKButtonText) && mOKButtonIcon == null) {
            mOKButton.setVisibility(View.GONE);
        } else {
            mOKButton.setText(mOKButtonText);
            if (mOKButtonIcon != null) {
                mOKButtonIcon.setBounds(0, 0, mButtonIconDimen, mButtonIconDimen);
                mOKButton.setCompoundDrawables(mOKButtonIcon, null, null, null);
            }
            mOKButton.setVisibility(View.VISIBLE);
            whichButtons = whichButtons | BIT_BUTTON_NEGATIVE;
        }

        if (shouldCenterSingleButton(mContext)) {
            /*
             * If we only have 1 button it should be centered on the layout and
             * expand to fill 50% of the available space.
             */
            if (whichButtons == BIT_BUTTON_POSITIVE) {
                centerButton(mCancelButton);
            } else if (whichButtons == BIT_BUTTON_NEGATIVE) {
                centerButton(mOKButton);
            }
        }

        final boolean hasButtons = whichButtons != 0;
        if (!hasButtons) {
            buttonPanel.setVisibility(View.GONE);
        }
    }

    private void centerButton(Button button) {
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) button.getLayoutParams();
        params.gravity = Gravity.CENTER_HORIZONTAL;
        params.weight = 0.5f;
        button.setLayoutParams(params);
    }

    public static class AlertParams {
        public final Context mContext;

        public int mIconId = 0;
        public Drawable mIcon;
        public int mIconAttrId = 0;
        public CharSequence mTitle;
        public CharSequence mMessage;
        public CharSequence mPositiveButtonText;
        public Drawable mPositiveButtonIcon;
        public DialogInterface.OnClickListener mPositiveButtonListener;

        public CharSequence mNegativeButtonText;
        public Drawable mNegativeButtonIcon;
        public DialogInterface.OnClickListener mNegativeButtonListener;

        public boolean mCancelable;
        public DialogInterface.OnCancelListener mOnCancelListener;
        public DialogInterface.OnDismissListener mOnDismissListener;
        public DialogInterface.OnKeyListener mOnKeyListener;
        public boolean mForceInverseBackground;
        public boolean fullScreen;

        public AlertParams(Context context) {
            mContext = context;
            mCancelable = true;
        }

        public void apply(MessageController dialog) {
            if (mTitle != null) {
                dialog.setTitle(mTitle);
            }
            if (mIcon != null) {
                dialog.setIcon(mIcon);
            }
            if (mIconId != 0) {
                dialog.setIcon(mIconId);
            }
            if (mIconAttrId != 0) {
                dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
            }
            if (mMessage != null) {
                dialog.setMessage(mMessage);
            }
            dialog.setFullScreen(fullScreen);
            if (mPositiveButtonText != null || mPositiveButtonIcon != null) {
                dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText, mPositiveButtonListener, null, mPositiveButtonIcon);
            }
            if (mNegativeButtonText != null || mNegativeButtonIcon != null) {
                dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText, mNegativeButtonListener, null, mNegativeButtonIcon);
            }
        }
    }

}
